// -*- C++ -*-
//
//  This file is part of CBNSIM, the Content-Based Networking
//  Simulation Library.
//
//  Authors: See the file AUTHORS for full details.
//
//  Copyright (C) 2002-2004 University of Colorado
//
//  This program is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public License
//  as published by the Free Software Foundation; either version 2
//  of the License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
//  USA, or send email to serl@cs.colorado.edu.
//
// $Id: WorkloadGenerator.h,v 1.2 2004/01/08 16:02:17 rutherfo Exp $
//
#ifndef CBNSIM_WORKLOADGENERATOR_H
#define CBNSIM_WORKLOADGENERATOR_H

#include <iostream>
#include <vector>
#include <set>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#include "cbnsim/WorkloadNodeProcessFactory.h"

namespace cbnsim
{
  /** @brief Main workload generator class. The workload events that
   * are generated by this class can be customized by adding
   * <code>WorkloadNodeProcessFactory</code> instances as required.
   */
  class WorkloadGenerator
    {
    public:
      /** @brief Constructor allows the output stream to
       * be set.
       */
      WorkloadGenerator( std::ostream& out = std::cout );

      /** @brief Destructor deletes any node or link process
       * factories that have been added.
       */
      virtual ~WorkloadGenerator();

      /** @brief Add a node process factory to the internal list.
       *
       * The WorkloadGenerator is responsible for managing the memory
       * associated with the WorkloadNodeProcessFactory.
       */
      void add( WorkloadNodeProcessFactory* wnpf );
      
      /** @brief set times (length and time unit ) for the workload file
       * 
       */
      int set_times( );
      
      /** @brief initialize static routing and write it in the workload file
       *
       */
      int init_routing( );
      
      /** @brief read client file for input process
       *
       */
      int read_clients();
      
      /** @brief publish content, writing them in the workload file
       *
       */
      int publishing_content( );
      
      /** @brief initialize static routing and write it in the workload file
       *
       */
      int create_input_process( );
      
      /** @brief generate process of downlaod content and write it in the workload file
       * 
       */
      void download_process( );

      /** @brief Sets the SSBG <code>attr_max</code> parameter.
       *
       * Default is 10.
       */
      void attr_max( int attr_max )
      { m_attr_max = attr_max; }

      /** @brief Returns the SSBG <code>attr_max</code> parameter.
       */
      int attr_max() const
      { return m_attr_max; } 

      /** @brief Sets the SSBG <code>attr_min</code> parameter.
       *
       * Default is 1.
       */
      void attr_min( int attr_min )
      { m_attr_min = attr_min; }

      /** @brief Returns the SSBG <code>attr_min</code> parameter.
       */
      int attr_min() const
      { return m_attr_min; } 

      /** @brief Sets the SSBG <code>constr_max</code> parameter.
       *
       * Default is 5.
       */
      void constr_max( int constr_max )
      { m_constr_max = constr_max; }

      /** @brief Returns the SSBG <code>constr_max</code> parameter.
       */
      int constr_max() const
      { return m_constr_max; } 

      /** @brief Sets the SSBG <code>constr_min</code> parameter.
       *
       * Default is 1.
       */
      void constr_min( int constr_min )
      { m_constr_min = constr_min; }

      /** @brief Returns the SSBG <code>constr_min</code> parameter.
       */
      int constr_min() const
      { return m_constr_min; } 

      /** @brief Sets value to use for the SSBG dist directory.
       *
       * Defaults to <code>$prefix/package-version/share/dist</code>.
       */
      void dist_dir( const std::string& dist_dir )
      { m_dist_dir = dist_dir; }

      /** @brief Returns the value used for the SSBG dist directory.
       */
      const std::string& dist_dir() const
      { return m_dist_dir; } 

      /** @brief Sets the SSBG <code>filt_max</code> parameter.
       *
       * Defaults to 20.
       */
      void filt_max( int filt_max )
      { m_filt_max = filt_max; }

      /** @brief Returns the SSBG <code>filt_max</code> parameter.
       */
      int filt_max() const
      { return m_filt_max; } 

      /** @brief Sets the SSBG <code>filt_min</code> parameter.
       *
       * Defaults to 0.
       */
      void filt_min( int filt_min )
      { m_filt_min = filt_min; }

      /** @brief Returns the SSBG <code>filt_min</code> parameter.
       */
      int filt_min() const
      { return m_filt_min; } 

      /** @brief Main entry point for the workload generator.
       */
      int main( const std::string& prog, const std::vector<std::string>& args )
	throw ( std::exception );

      /** @brief Sets the p command.
       *
       * Valid values are 'ALL', '<int>' or '<real>%'. Default is '0'.
       */
      void p_cmd( const std::string& p_cmd )
      { m_p_cmd = p_cmd; }

      /** @brief Returns the p command.
       */
      const std::string& p_cmd() const
      { return m_p_cmd; } 

      /** @brief Sets the SSBG <code>reuse_types</code> parameter.
       *
       * Default is 'false'.
       */
      void reuse_types( bool reuse_types )
      { m_reuse_types = reuse_types; }

      /** @brief Returns the SSBG <code>reuse_types</code> parameter.
       */
      bool reuse_types() const
      { return m_reuse_types; } 

      /** @brief Sets the s command.
       *
       * Valid values are 'ALL', '<int>' or '<real>%'. Defaults to '0'.
       */
      void s_cmd( const std::string& s_cmd )
      { m_s_cmd = s_cmd; }

      /** @brief Returns the s command.
       */
      const std::string& s_cmd() const
      { return m_s_cmd; } 

      /** @brief Sets the random seed to be used.
       * 
       * Default is the current time in milliseconds.
       */
      void seed( long seed )
      { m_seed = seed; }

      /** @brief Returns the random seed.
       */
      long seed() const
      { return m_seed; }

      /** @brief Sets the sim_length parameter.
       *
       * Default to 0.
       */
      void sim_length( int sim_length )
      { m_sim_length = sim_length; }

      /** @brief Returns the sim_length parameter.
       */
      int sim_length() const
      { return m_sim_length; } 
      
      /** @brief Sets the files file name to use.
       *
       * Default is empty.
       */
      void files_file( const std::string& files_file )
      { m_files_file = files_file; }

      /** @brief Returns the files file name.
       */
      const std::string& files_file() const
      { return m_files_file; }

      /** @brief Sets the workload time unit, default is 1.0.
       */
      void wtu_sec( double wtu_sec )
      { m_wtu_sec = wtu_sec; }

      /** @brief Returns workload time unit.
       */
      double wtu_sec() const
      { return m_wtu_sec; } 
      
      
    private:
      std::ostream & output_attr( std::ostream& out, 
					  const std::string& x, 
				     const std::string& o, 
				     const std::string& v)
	{
	  return out << x << ' ' << o << ' ' << '"' << v << '"';
	}

      template<class T>
	std::ostream & output_attr(std::ostream & out, 
					   const std::string & x, 
					   const std::string & o, 
					   T v )
	{
	  return out << x << ' ' << o << ' ' << v;
	}
      
      void parse_args( const std::vector<std::string>& args ) throw ( argument_exception );

      void print_usage( const char* error = NULL );
      
      typedef struct{
	string distribution;
	double rate;
      } client;

      unsigned int				m_attr_max;
      unsigned int				m_attr_min;
      unsigned int				m_constr_max;
      unsigned int				m_constr_min;
      std::string				m_dist_dir;
      unsigned int				m_filt_max;
      unsigned int				m_filt_min;
      std::vector<WorkloadNodeProcessFactory*>	m_npfs;
      std::ostream&				m_out;
      std::string				m_p_cmd;
      bool					m_reuse_types;
      std::string				m_s_cmd;
      long					m_seed;
      double					m_sim_length;
      double					m_wtu_sec;
      unsigned int 				m_file_per_class;
      double					m_sim_load_cache_time;
      double					m_sim_load_cache_lambda;
      double					m_alpha;
      bool					m_man_routing;
      std::string				m_files_file;   
      std::string				m_prefix_file;
      std::string				m_multipath;
      std::string				m_clients_file;
      std::string				m_str_dist;
      std::map<int,client>			m_client_map;
      std::vector<string>			m_prefix;
      std::vector<string>			m_clients;
      std::vector<string>			m_files;
      std::vector< vector<string> >		m_files_token;
      std::multimap<ssim::Time, std::string>    m_event_map;  
      ssim::Time				time;
      double					ts;
    };
};
#endif
